#import "Alexandra.h"
#import "Article.h"
#import "descriptors.h"
#import "headerfields.h"
#import "parsedate.h"
#import "rfc822realname.h"
#import "parse-header.h"
#import "plain-subject.h"

#import <time.h>
#import <misckit/MiscAppDefaults.h>
#import "Preferences.subproj/preferences.h"

static BOOL showAuthor,showSubject,showSize;
static int	smallIs,largeIs;
static int sortType=0;

@implementation Article

+ initialize				// Ein Article wird erst erzeugt nachdem das main-nib
	{						// geladen wurde, d.h. die Default-Defaults sind schon
						  	// vom Preferences Manager gesetzt!
	if(self==[Article class])
		{
		[self prefsChanged];
		[ERROR_MANAGER addObserver:self 
			selector:@selector(prefsChanged) forError:ENOTEPrefsChanged];
		}
	return self;
	}


+ prefsChanged;
	{
	showAuthor=[NXApp defaultBoolValue:DEFAULT_SHOW_AUTHOR];	
	showSubject=[NXApp defaultBoolValue:DEFAULT_SHOW_SUBJECT];	
	showSize=[NXApp defaultBoolValue:DEFAULT_SHOW_SIZE];
	smallIs=[NXApp defaultIntValue:DEFAULT_SMALL_ARTICLE];	
	largeIs=[NXApp defaultIntValue:DEFAULT_LARGE_ARTICLE];	
	return self;
	}

+ setSortType:(int)t
{
	sortType=t;
	
	return self;
}

+ (int)sortType
{
	return sortType;
}

- initWithNumber:(long)number
{
   [self initTextCell:NULL];
   [self setWrap:NO];
   size=0;
   unread=TRUE;
   myNumber=number;
   myHeader.fieldBody=(char **)calloc(FIELD_COUNT,sizeof(char *));
   timeOfPosting=0;
   authorRealName=NULL;
   killed=FALSE;
   return self;
}

- composeTitle
{
   char *buf,*p=NULL;
	BOOL a=FALSE;
	BOOL b=FALSE;
	int from,to,tsize=1;
	
	if(showSubject && (p=myHeader.fieldBody[SUBJECT])){
	   a=TRUE;
		tsize+=strlen(p);
	}
	
	if(showAuthor && (myHeader.fieldBody[FROM]!=NULL)){
      rfc822_realname(myHeader.fieldBody[FROM],&from,&to);
         if(from<to)
				b=TRUE;
				tsize+=to-from+6;
	}

	buf=calloc(tsize,sizeof(char));
	if(a) strcpy(buf,p);
	if(b){
   	strcat(buf," (");
      strncat(buf,myHeader.fieldBody[FROM]+from,to-from+1);
      strcat(buf,")");
   }
 

   [self setStringValueNoCopy:buf shouldFree:YES];
	
	return self;
}

- parseHeader:(NXStream *)headerStream;
{
   char *stream_buffer;
   int len,a;

   NXGetMemoryBuffer(headerStream,&stream_buffer,&len,&a);
   parse_header(stream_buffer, len, myHeader.fieldBody, h_field_name, FIELD_COUNT,YES);

   return self;
}

-free
{
   int i;

   for(i=0;i<FIELD_COUNT;i++)
      if(myHeader.fieldBody[i]!=NULL)
         free(myHeader.fieldBody[i]);
   free(myHeader.fieldBody);
   if(authorRealName!=NULL)
      free(authorRealName);
   return([super free]);
}

- (long)number
{
   return myNumber;
}

- (headerDesc *)header
{
   return &myHeader;
}

- (time_t)time
{
   if((timeOfPosting==0)&&(myHeader.fieldBody[DATE]!=NULL)){
      timeOfPosting=parsedate(myHeader.fieldBody[DATE]);
      if(timeOfPosting==-1){
         timeOfPosting=0;
         free(myHeader.fieldBody[DATE]);
         myHeader.fieldBody[DATE]=NULL;
      }
   }

   return timeOfPosting;
}

- (const char *)realName;
{
   if((authorRealName==NULL)&&(myHeader.fieldBody[FROM]!=NULL)){
      int from,to;
      rfc822_realname(myHeader.fieldBody[FROM],&from,&to);
      if(from<to){
         authorRealName=(char *)malloc((to-from+2)*sizeof(char));
         strncpy(authorRealName,myHeader.fieldBody[FROM]+from,to-from+1);
         authorRealName[to-from+1]='\0';
      }
   }

   return authorRealName;
}

- setRead
{
   unread=FALSE;
   return self;
}

- setUnread
{
   unread=TRUE;
   return self;
}

- (BOOL)isRead
{
   return((unread==FALSE)||(killed==TRUE));
}

- kill
{
   killed=TRUE;
   return self;
}

- unkill
{
   killed=FALSE;
   return self;
}

- (BOOL)isKilled
{
   return killed;
}

- setTextAttributes:textObj
{
   [super setTextAttributes:textObj];
   if (unread==FALSE)
      [textObj setTextGray:NX_DKGRAY];
   else
      [textObj setTextGray:NX_BLACK];      
   return textObj;
}

- unsetTag
{
   myTag=0;
   return self;
}

- setTag
{
   myTag=1;
   return self;
}

- (BOOL)isTaged
{
   return((myTag==1)&&(killed==FALSE));
}

- (int)size
{
   return size;
}

- setSize:(int)asize;
{
   size=asize;
   return self;
}



- (int)lines;
	{
	return lines;
	}


- setLines:(int)lineCount;
	{
	lines=lineCount;
	return self;
	}
	
//------------------------------------
// MiscCompare protocol implementation
//------------------------------------
- (int)compare:anObject
{
  int result=0;
  BOOL r1,r2;
  const char *s1,*s2;
  headerDesc *h1,*h2;

  switch (sortType) {
    case SORT_BY_DATE:
       result=[self time]-[anObject time];
       break;
    case SORT_BY_SUBJECT:
	 	 h1=[self header];
		 h2=[anObject header];
		 if(!h1 || !h2){
		 	NXLogError("Article.m: article header is NULL pointer");
			return 0;
		 }
       s1=plain_subject(h1->fieldBody[SUBJECT],&r1);
       s2=plain_subject(h2->fieldBody[SUBJECT],&r2);

       if((s1==NULL)&&(s2==NULL)) result=0;
       else if(s1==NULL) result=-1;
       else if(s2==NULL) result=1;
       else
          result=strcasecmp(s1,s2);
       if(result==0)
          if(r1!=r2)
             result=(r1? 1:-1);
          else
             result=[self time]-[anObject time];
       break;
    case SORT_BY_NUMBER:
       result=[self number]-[anObject number];
       break;
    case SORT_BY_REAL_NAME:
       s1=[self realName];
       s2=[anObject realName];
       if((s1==NULL)&&(s2==NULL)) result=0;
       else if(s1==NULL) result=-1;
       else if(s2==NULL) result=1;
       else
          result=strcasecmp(s1,s2);
       break;
  }

  return result;
}

//-----------------------------------------------------------
// fancy drawing...
//-----------------------------------------------------------

#define IMAGEMARGIN 1.0

- calcCellSize:(NXSize *)theSize inRect:(const NXRect *)aRect
	{
	[super calcCellSize:theSize inRect:aRect];
	theSize->height+=1;
	return self;
	}


- drawInside:(const NXRect *)cellFrame inView:controlView
	{
    static NXImage	*dotImages[] = { nil, nil, nil };
    NXRect 			rect = *cellFrame;
    NXPoint 		imageOrigin;
    NXSize 			dotSize;
	int				sizecat;
	struct _cFlags1	buf;
        
    if(!dotImages[0])
		{
		dotImages[0] = [NXImage findImageNamed:"Article-short"];
		dotImages[1] = [NXImage findImageNamed:"Article-medium"];
		dotImages[2] = [NXImage findImageNamed:"Article-long"];
		}		
	[dotImages[2] getSize:&dotSize];

    PSsetgray((cFlags1.state || cFlags1.highlighted) ? NX_WHITE : NX_LTGRAY);
    NXRectFill(cellFrame);

	if(showSize && (lines>0))
		{
		imageOrigin.x = NX_MAXX(cellFrame) - IMAGEMARGIN * 2.0 - dotSize.width;
		imageOrigin.y = NX_Y(cellFrame) + NX_HEIGHT(cellFrame) -
						(NX_HEIGHT(cellFrame) - dotSize.height) / 2.0;
		if(lines<=smallIs)
			sizecat=0;
		else if(lines<=largeIs)
			sizecat=1;
		else
			sizecat=2;
		[dotImages[sizecat] composite:NX_SOVER toPoint:&imageOrigin];
		NX_WIDTH(&rect) -= (dotSize.width + IMAGEMARGIN * 2.0 - NX_X(&rect));
		}
	buf=cFlags1;
	cFlags1.highlighted=cFlags1.state=0;
    [super drawInside:&rect inView:controlView];
    cFlags1=buf;
	
    PSsetgray(NX_DKGRAY);
    if (cFlags1.state || cFlags1.highlighted)
		{
        NXRect rectArray[2];

		NXSetRect(&(rectArray[0]),NX_X(cellFrame),NX_Y(cellFrame),
				NX_WIDTH(cellFrame),1);
		NXSetRect(&(rectArray[1]),NX_X(cellFrame),NX_MAXY(cellFrame)-1,
				NX_WIDTH(cellFrame), 1.0);
		NXRectFillList(rectArray, 2);
    	}
    return self;
	}


- highlight:(const NXRect *)cellFrame inView:controlView lit:(BOOL)flag
	{
    if(cFlags1.highlighted != flag)
		{
		cFlags1.highlighted = flag;
		[self drawInside:cellFrame inView:controlView];
    	}
    return self;
	}



@end
